/*
 * @Author: xiaosihan
 * @Date: 2024-08-15 10:35:24
 * @Last Modified by: xiaosihan
 * @Last Modified time: 2024-08-17 00:11:40
 */

import { uniq } from "lodash";
import cloneDeep from "lodash/cloneDeep";
import { Euler, Group, Vector3 } from "three";
import InstancedMeshBase from "three-base/InstancedMeshBase";

// 多模型数据结构
export type ManyModelData = {
    id: string,
    name: string,
    url: string,
    position?: {
        x: number,
        y: number,
        z: number,
    },
    rotation?: {
        x: number,
        y: number,
        z: number,
    },
    scale?: {
        x: number,
        y: number,
        z: number,
    },
}

// 大量的模型组对象
// 用于处理大量的重复的模型
export default class ManyModelGroup extends Group {
    declare children: InstancedMeshBase[];

    //根据url 获取实例模型组, 没有就创建一个新的
    getInstanceMeshGroupByUrl(url: string): InstancedMeshBase {
        let instanceMeshGroup = this.children.find(o => o.url === url);
        if (!instanceMeshGroup) {
            instanceMeshGroup = new InstancedMeshBase(url);
            this.add(instanceMeshGroup);
        }
        return instanceMeshGroup;
    }

    // 保存数据
    datas: Array<ManyModelData> = [];
    async setDatas(datas: Array<ManyModelData> = []) {
        this.datas = [...datas];
        //按照url 分组
        const urls = uniq(datas.map(d => d.url));
        //显示有效的模型组
        this.children.map(o => o.visible = urls.includes(o.url));

        // 遍历 url 获取相同的url的数据
        for (let url of urls) {
            const modelDatasWithUrl = datas.filter(d => d.url === url);
            // 按照 url来获取 InstanceMeshGroup 对象
            const instanceMeshGroup = this.getInstanceMeshGroupByUrl(url);
            // 设置实例数量
            instanceMeshGroup.setCount(modelDatasWithUrl.length);

            for (let i = 0; i < modelDatasWithUrl.length; i++) {
                const { position, rotation, scale } = modelDatasWithUrl[i];
                if (position) {
                    instanceMeshGroup.setTRS(i, { position: new Vector3(position.x, position.y, position.z) });
                }
                if (rotation) {
                    instanceMeshGroup.setTRS(i, { rotation: new Euler(rotation.x, rotation.y, rotation.z) });
                }
                if (scale) {
                    instanceMeshGroup.setTRS(i, { scale: new Vector3(scale.x, scale.y, scale.z) });
                }
            }

        }

    }
    getDatas() {
        return cloneDeep(this.datas);
    }
    addData(data: ManyModelData) {
        this.setDatas([...this.datas, data]);
    }
    delData(id: string) {
        this.setDatas([...this.datas.filter(d => d.id !== id)]);
    }
    updataData(id: string, data: Partial<Omit<ManyModelData, "id">>) {
        this.datas.map(d => {
            if (d.id === id) {
                Object.assign(data, d);
            }
        });
        this.setDatas(this.datas);
    }

}